<template>
  <q-page class="q-pa-md">
    <div class="q-pb-md text-h5">{{pageTitle}} <span class="text-subtitle1">数据表的演示</span></div>
    <div class="text-h5">静态表格</div>
    <div class="row">
      <div class="col-12 q-py-sm">
        <q-toggle dense v-model="$d.isStaticTableWrap" label="折行" />
      </div>
      <div class="col-12 col-lg-8 scroll">
        <table class="simple-static-table text-no-wrap">
          <tr>
            <th>SKU</th>
            <th>品名</th>
            <th>规格型号</th>
            <th>价格</th>
            <th>发布日期</th>
            <th>描述</th>
          </tr>
          <tr v-for="(sku, idx) in $d.skus" :key="idx">
            <td> {{sku.sku}}</td>
            <td> {{sku.skuName}}</td>
            <td> {{sku.spec}}</td>
            <td> {{sku.price}}</td>
            <td> {{fmt.dtFmtDateOnly(sku.releaseDt)}}</td>
            <td :style="staticTableDescStyle"> {{sku.desc}}</td>
          </tr>
        </table>
      </div>
    </div>

    <div class="text-h5 q-mt-md">QTable</div>
    <div class="row">
      <div class="col-12 q-py-sm">
        <q-toggle dense v-model="$d.isDynamicTableWrap" label="折行" />
      </div>
      <div class="col-12 col-lg-8 scroll simple-border">
        <q-table :columns="columnsInfoSkus" :rows="$d.skus" :hide-pagination="true" dense hide-selected-banner
          no-data-label="没有数据" row-key="sku" separator="cell" table-style="table-layout:fixed;" binary-state-sort>
          <template v-slot:body-cell-desc="props">
            <q-td :props="props">
              <div v-html="props.row.desc"></div>
            </q-td>
          </template>
        </q-table>
      </div>
    </div>

    <div class="text-h5 q-mt-md">整行点击选择</div>
    <div class="row">
      <div class="col-12 q-py-sm">
        好像没有什么特别好的通用做法实现这种效果，目前是利用<code>@row-click</code>事件来改变<code>v-model:selected</code>的内容来实现的
      </div>
      <div class="col-12 col-lg-6 col-md-8 scroll simple-border">
        <q-table :columns="columnsInfoSkusLite" :rows="$d.skus" :hide-pagination="true" dense hide-selected-banner
          no-data-label="没有数据" row-key="sku" separator="cell" selection="multiple" v-model:selected="$d.selectedSkus"
          color="primary" @row-click="onRowClick">
        </q-table>
      </div>
    </div>

    <div class="text-h5 q-mt-md">核算科目（可折叠表展示）</div>
    <div class="row">
      <div class="col-12 q-py-sm q-gutter-sm">
        <q-btn color="primary" @click="collapseAll">折叠</q-btn>
        <q-btn color="primary" @click="expandToGrade2">展开至二级科目</q-btn>
        <q-btn color="primary" @click="expandAll">展开全部</q-btn>
      </div>
      <div class="col-lg-6 col-md-8 col-sm-12 simple-border">
        <q-table :rows="$d.budgetItems" :hide-pagination="true" dense
          hide-selected-banner :pagination="paginationBudgetItems" no-data-label="没有数据" row-key="budgetCode"
          separator="cell" flat>
          <template v-slot:header="props">
            <q-tr :props="props">
              <q-th style="width: 120px">科目代码</q-th>
              <q-th style="width: 80px">科目级别</q-th>
              <q-th>科目名称</q-th>
              <q-th style="width: 100px">收入/支出</q-th>
              <q-th style="width: 80px">是否有效</q-th>
            </q-tr>
          </template>

          <template v-slot:body="props">
            <q-tr :props="props" v-show="isRowVisible(props.row.budgetCode)"
              :class="getBudgetItemRowClass(props.row.budgetCode)">
              <q-td :style="getBudgetCodeColStyle(props.row.budgetCode)">
                <q-btn padding="none" size="md" color="primary" flat dense
                  @click="toggleRowExpandedState(props.row.budgetCode)"
                  :icon="isRowExpanded(props.row.budgetCode) ? 'eva-minus-square' : 'eva-plus-square'"
                  v-if="props.row.budgetCode.length===3||props.row.budgetCode.length===5"></q-btn>
                <q-icon size="xs" color="grey-6" name="fiber_manual_record"
                  v-if="props.row.budgetCode.length===7"></q-icon>
                {{props.row.budgetCode}}
              </q-td>
              <q-td>
                {{props.row.grade}}
              </q-td>
              <q-td>
                {{props.row.budgetName}}
              </q-td>
              <q-td>
                {{props.row.budgetType}}
              </q-td>
              <q-td :class="props.row.isEnabled?'text-positive':'text-negative'">
                {{props.row.isEnabled ? '是' : '否'}}
              </q-td>
            </q-tr>
          </template>
        </q-table>
      </div>
    </div>
    <div class="text-h5 q-mt-md">冻结行和列的DEMO</div>
    <div class="row">
      <div class="col-12 q-py-sm">
        不管是行还是列，要实现冻结，必须确定表格的宽和高，宽比较好说，而高如果确定的话往往会出现表格内滚动条和窗口本身的滚动条，体验并不好，
        且不同的屏幕，高应该固定为多少也不好说，所以我们现在只做到在表格全屏显示的时候冻结其某些行即可(此时表格的高是确定的)。
        另外，被冻结的行的高度，被冻结的列的宽度，是必须固定的，而q-table的列宽默认是auto，即随着单元格内容而变化，直接用width控制还不行，需要用min-width。
      </div>
      <div class="col-12 simple-border">
        <q-table :rows="$d.biForm" :columns="biColumnsInfo" separator="cell" row-key="biNameGrade3Disp" dense flat
          :hide-pagination="true" color="primary" :pagination="biPaginationInfo" class="generic-sticky-header-table">
          <!--:visible-columns 控制切换-->
          <template v-slot:top="props">
            <span>从</span>
            <simple-filter-select :options="$d.monthCN" option-label="label" option-value="value" :clearable="false"
              v-model="budgetFromMonth" style="width: 70px" class="q-ml-xs" :use-filter="false"></simple-filter-select>
            <span class="q-ml-xs">月&nbsp;至</span>
            <simple-filter-select :options="$d.monthCN" option-label="label" option-value="value" :clearable="false"
              v-model="budgetToMonth" style="width: 70px" class="q-ml-xs" :use-filter="false"></simple-filter-select>
            <span class="q-ml-xs">月</span>
            <!--填充所有剩余空间-->
            <q-space />
            <q-btn flat dense :icon="props.inFullscreen ? 'fullscreen_exit' : 'fullscreen'"
              :title="props.inFullscreen ? '退出全屏' : '全屏显示'" @click="props.toggleFullscreen" class="q-ml-sm"
              :ripple="false" />
          </template>

          <!-- 直接通过columnInfo的headerClass来指定样式会存在一个因为样式加了scoped而不生效的问题，不得不直接用插槽来指定 -->
          <template v-slot:header="props">
            <q-tr :props="props">
              <template v-for="col in props.cols" :key="col.name">
                <q-th v-if="col.name==='一级科目'" class="sticky-column-cell1" style="z-index: 2">
                  {{col.label}}
                </q-th>
                <q-th v-else-if="col.name==='二级科目'" class="sticky-column-cell2" style="z-index: 2">
                  {{col.label}}
                </q-th>
                <q-th v-else-if="col.name==='三级科目'" class="sticky-column-cell3" style="z-index: 2">
                  {{col.label}}
                </q-th>
                <q-th v-else>
                  {{col.label}}
                </q-th>
              </template>
            </q-tr>
          </template>
          <template v-slot:body="props">
            <q-tr :props="props" no-hover
              :class="props.row.biNameGrade2 === '项目合计' ? 'bg-grey-4 ' : (props.row['biNameGrade3'] === '小计' ? 'bg-grey-3' : '')">
              <template v-for="(item, idx) in biColumnsInfo" :key="idx">
                <template v-if="item.field==='biNameGrade1Disp'">
                  <q-td v-if="isFirstRow(props.row, 'biNameGrade1Disp')"
                    :rowspan="calculateRowSpan(props.row, 'biNameGrade1Disp')" class="sticky-column-cell1 bg-white">
                    {{props.row['biNameGrade1Disp']}}
                  </q-td>
                </template>
                <template v-else-if="item.field==='biNameGrade2Disp'">
                  <q-td v-if="isFirstRow(props.row, 'biNameGrade2Disp') || props.row['biNameGrade2Disp']==='项目合计'"
                    :rowspan="calculateRowSpan(props.row, 'biNameGrade2Disp')"
                    :colspan="props.row['biNameGrade2'] === '项目合计' ? 2 : 1"
                    :class="'force-left-border sticky-column-cell2 '+(props.row['biNameGrade2']==='项目合计'?'bg-grey-4':'bg-white')">
                    {{props.row['biNameGrade2'] === '项目合计' ? '项目合计' : props.row['biNameGrade2Disp']}}
                  </q-td>
                </template>
                <template v-else-if="item.field==='biNameGrade3Disp'">
                  <q-td v-if="props.row['biNameGrade3'] !== '项目合计'"
                    :class="'force-left-border sticky-column-cell3 '+(props.row['biNameGrade3']==='小计'?'bg-grey-3':'bg-white')">
                    {{props.row['biNameGrade3'] === '小计' ? '小计' : props.row['biNameGrade3Disp']}}
                  </q-td>
                </template>
                <template v-else>
                  <q-td>
                    {{props.row[item.field]}}
                  </q-td>
                </template>
              </template>
            </q-tr>
          </template>
        </q-table>
      </div>
    </div>
  </q-page>
</template>

<script lang="ts" setup>
import {useTitleHelper} from 'src/lib/hooks/titleHelper'
import {computed, reactive, ref} from 'vue'
import {ColumnInfo} from 'src/lib/defs/comm'
import _ from 'lodash'
import {budgetData, budgetItems, monthList, skuData, SkuInfo} from './DatatableData'
import SimpleFilterSelect from 'src/lib/components/SimpleFilterSelect.vue'

const pageTitle = 'Datatable DEMO'
useTitleHelper(pageTitle)

const $d = reactive({
  //数据列表...
  skus: skuData as SkuInfo[],
  selectedSkus: [] as SkuInfo[],
  budgetItems: budgetItems,
  monthCN: monthList,
  biForm: budgetData,

  budgetItemsExpandedInfo: {} as Record<string, boolean>,
  // 静态表格是否折行
  isStaticTableWrap: false,
  // 动态表格（QTable）是否折行
  isDynamicTableWrap: false,
})

// 不分页
let biPaginationInfo = {
  page: 1,
  rowsPerPage: 0,
}

const biColumnsInfo = computed(() => {
  const columnInfo: ColumnInfo[] = [
    {label: '一级科目', name: '一级科目', field: 'biNameGrade1Disp', align: 'center'},
    {label: '二级科目', name: '二级科目', field: 'biNameGrade2Disp', align: 'center'},
    {label: '三级科目', name: '三级科目', field: 'biNameGrade3Disp', align: 'center'},
  ]
  _.forEach($d.monthCN, (m) => {
    if(m.value>=budgetFromMonth.value && m.value<=budgetToMonth.value) {
      columnInfo.push({label: m.label + '月预算', name: m.label + '月预算', field: 'budgetMonth' + m.value})
      columnInfo.push({label: m.label + '月决算', name: m.label + '月决算', field: 'prevAbaMonth' + m.value})
      columnInfo.push({label: '去年同期', name: '去年同期', field: 'lastPrevAbaMonth' + m.value})
    }
  })

  return columnInfo
})

const onRowClick = function (evt: Event, row: SkuInfo) {
  let idx = _.indexOf($d.selectedSkus, row)
  if (idx >= 0) {
    _.pull($d.selectedSkus, row)
  } else {
    $d.selectedSkus.push(row)
  }
}

//返回true表示处于展开中，返回false表示收拢中，返回null表示不需要展开收拢（三级科目）
const isRowExpanded = (code: string) => {
  if (code.length == 3 || code.length == 5) {
    return $d.budgetItemsExpandedInfo[code]
  }
  return true
}

//返回true表示行处于可见状态，返回false表示行处于隐藏状态
const isRowVisible = (code: string) => {
  if (code.length == 7) {
    return $d.budgetItemsExpandedInfo[code.substring(0, 5)] && $d.budgetItemsExpandedInfo[code.substring(0, 3)]
  }
  if (code.length == 5) {
    return $d.budgetItemsExpandedInfo[code.substring(0, 3)]
  }
  return true
}

const toggleRowExpandedState = (code: string) => {
  $d.budgetItemsExpandedInfo[code] = !($d.budgetItemsExpandedInfo[code])
}

const getBudgetItemRowClass = (code: string) => {
  if (code.length == 3) {
    return 'bg-grey-2'
  }
  if (code.length == 5) {
    return 'bg-grey-1'
  }
  return ''
}

const getBudgetCodeColStyle = (code: string) => {
  if (code.length == 7) {
    return 'padding-left:40px'
  }
  if (code.length == 5) {
    return 'padding-left:20px'
  }
  return ''
}

const collapseAll = function () {
  _.forEach($d.budgetItems, (item) => {
    if (item.budgetCode.length == 3 || item.budgetCode.length == 5) {
      $d.budgetItemsExpandedInfo[item.budgetCode] = false
    }
  })
}

const expandToGrade2 = function () {
  _.forEach($d.budgetItems, (item) => {
    if (item.budgetCode.length == 3) {
      $d.budgetItemsExpandedInfo[item.budgetCode] = true
    }
    if (item.budgetCode.length == 5) {
      $d.budgetItemsExpandedInfo[item.budgetCode] = false
    }
  })
}

const expandAll = function () {
  _.forEach($d.budgetItems, (item) => {
    if (item.budgetCode.length == 3 || item.budgetCode.length == 5) {
      $d.budgetItemsExpandedInfo[item.budgetCode] = true
    }
  })
}

const columnsInfoSkus: ColumnInfo[] = [
  {
    label: 'SKU',
    name: 'sku',
    field: 'sku',
    align: 'left',
    defOrder: 1,
    defVisible: true,
    sortable: true,
  },
  {
    label: '品名',
    name: 'skuName',
    field: 'skuName',
    align: 'left',
    defOrder: 2,
    defVisible: true,
    sortable: true,
  },
  {
    label: '规格型号',
    name: 'spec',
    field: 'spec',
    align: 'left',
    defOrder: 3,
    defVisible: true,
  },
  {
    label: '价格',
    name: 'price',
    field: 'price',
    align: 'left',
    defOrder: 4,
    defVisible: true,
    sortable: true,
  },
  {
    label: '发布日期',
    name: 'releaseDt',
    field: 'releaseDt',
    align: 'left',
    defOrder: 5,
    defVisible: true,
    format: (value: any) => $f.fmt.dtFmtDateOnly(value as string),
  },
  {
    label: '描述',
    name: 'desc',
    field: 'desc',
    align: 'left',
    defOrder: 5,
    defVisible: true,
    style: () => dynamicTableDescStyle.value,
  },
]

const columnsInfoSkusLite: ColumnInfo[] = [
  {
    label: 'SKU',
    name: 'sku',
    field: 'sku',
    align: 'left',
    defOrder: 1,
    defVisible: true,
  },
  {
    label: '品名',
    name: 'skuName',
    field: 'skuName',
    align: 'left',
    defOrder: 2,
    defVisible: true,
  },
  {
    label: '规格型号',
    name: 'spec',
    field: 'spec',
    align: 'left',
    defOrder: 3,
    defVisible: true,
  },
  {
    label: '价格',
    name: 'price',
    field: 'price',
    align: 'left',
    defOrder: 4,
    defVisible: true,
  }]

//预决算科目表分页信息
const paginationBudgetItems = {
  page: 1,
  rowsPerPage: 0, //无需分页
}

const staticTableDescStyle = computed(() => {
  return $d.isStaticTableWrap ? 'white-space: normal' : 'white-space: nowrap'
})

const dynamicTableDescStyle = computed(() => {
  return $d.isDynamicTableWrap ? 'white-space: normal' : 'white-space: nowrap'
})

const isFirstRow = function (row: any, name: string) {
  return (_.find($d.biForm, [name, row[name]]) === row)
}

const calculateRowSpan = function (item: any, name: string) {
  let num = 0
  _.forEach($d.biForm, (row) => {
    if (row[name] === item[name]) {
      num = num + 1
    }
  })
  return num
}

const budgetFromMonth = ref(1)
const budgetToMonth = ref(12)

const fmt = $f.fmt

expandAll()

</script>

<style lang="sass" scoped>
.force-left-border
  border-left: $layout-border !important

.sticky-column-cell1
  position: sticky
  left: 0
  min-width: 80px !important
  z-index: 1
  white-space: normal

.sticky-column-cell2
  position: sticky
  left: 80px
  z-index: 1
  min-width: 100px !important
  white-space: normal

.sticky-column-cell3
  position: sticky
  left: 180px
  z-index: 1
  min-width: 160px !important
  white-space: normal
</style>
